package com.spa.domain.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.spa.application.command.admin.ShopEditCommand;
import com.spa.application.dto.shop.ShopIncomeDTO;
import com.spa.application.query.admin.ShopQuery;
import com.spa.domain.entity.CitiesServed;
import com.spa.domain.entity.Massagist;
import com.spa.domain.entity.OrderInfo;
import com.spa.domain.entity.Profit;
import com.spa.domain.entity.Rule;
import com.spa.domain.entity.Shop;
import com.spa.infrastructure.enums.dict.order.OrderOperStatusEnum;
import com.spa.infrastructure.enums.dict.order.OrderStatusEnum;
import com.spa.infrastructure.exception.SpaException;
import com.spa.infrastructure.mapper.ShopMapperStruct;
import com.spa.infrastructure.repository.condition.CitiesServedCondition;
import com.spa.infrastructure.repository.condition.OrderInfoCondition;
import com.spa.infrastructure.repository.condition.RuleCondition;
import com.spa.infrastructure.repository.condition.ShopCondition;
import com.spa.infrastructure.repository.po.ShopPO;
import com.spa.infrastructure.repository.service.ShopRepositoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class ShopService {

    @Resource
    private ShopRepositoryService shopRepositoryService;

    @Autowired
    private CitiesServedService citiesServedService;
    @Autowired
    private MassagistService massagistService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private ProfitService profitService;
    @Resource
    private RuleService ruleService;

    public Page<Shop> pageShop(ShopQuery query) {
        ShopCondition condition = ShopMapperStruct.INSTANCE.query2Condition(query);
        condition.setOrderByCreateTimeDesc(true);
        Page<Shop> page = ShopMapperStruct.INSTANCE.po2Entity4Page(shopRepositoryService.page(condition));
        setCity(page.getRecords());
        setRule(page.getRecords());
        return page;
    }

    private void setCity(List<Shop> shops) {
        if (CollectionUtil.isEmpty(shops)) {
            return;
        }
        CitiesServedCondition condition = new CitiesServedCondition();
        condition.setIds(shops.stream().map(Shop::getCityId).toList());
        List<CitiesServed> citiesServedList = citiesServedService.listInfo(condition);
        Map<Long, CitiesServed> map = citiesServedList.stream().collect(Collectors.toMap(CitiesServed::getId, Function.identity()));
        shops.forEach(shop -> shop.setCity(map.get(shop.getCityId())));
    }

    private void setRule(List<Shop> shops) {
        if (CollectionUtil.isEmpty(shops)) {
            return;
        }
        RuleCondition condition = new RuleCondition();
        condition.setRelevanceIds(shops.stream().map(Shop::getId).toList());
        List<Rule> ruleList = ruleService.listRule(condition);

        Map<Long, List<Rule>> map = ruleList.stream().collect(Collectors.groupingBy(Rule::getRelevanceId));
        shops.forEach(shop -> shop.setRuleList(map.get(shop.getId())));

    }

    public Long addShop(ShopPO shopPO) {
        shopPO.setIsDel(0);
        shopPO.setFlag(1);
        return shopRepositoryService.add(shopPO);
    }

    public void editShop(ShopEditCommand command) {
        ShopPO po = ShopMapperStruct.INSTANCE.command2Po(command);
        if (BeanUtil.isEmpty(po, "id")) {
            return;
        }
        shopRepositoryService.updateShopById(po);
    }

    /**
     * 切换自动甩单状态
     * @param id
     * @param flag
     */
    public void switchFlag(Long id, int flag) {
        ShopPO po = new ShopPO();
        po.setId(id);
        po.setFlag(flag);
        shopRepositoryService.updateShopById(po);
    }

    public void offlineShop(Long id) {
        ShopPO po = new ShopPO();
        po.setId(id);
        po.setIsDel(1);
        shopRepositoryService.updateShopById(po);
    }

    public void onlineShop(Long id) {
        ShopPO po = new ShopPO();
        po.setId(id);
        po.setIsDel(0);
        shopRepositoryService.updateShopById(po);
    }

    public Shop getShopById(Long id) {
        Shop shop = ShopMapperStruct.INSTANCE.po2Entity(shopRepositoryService.getShopById(id));
        if (BeanUtil.isEmpty(shop)) {
            throw new SpaException("门店不存在");
        }
        setCity(Lists.newArrayList(shop));
        return shop;
    }

    public Shop getShopByName(String name) {
        ShopCondition condition = new ShopCondition();
        condition.setName(name);
        return ShopMapperStruct.INSTANCE.po2Entity(shopRepositoryService.getShopByCondition(condition));
    }

    /**
     * 统计全平台门店数量
     *
     * @return 门店数量
     */
    public Long countAllShop() {
        return shopRepositoryService.countByCondition(new ShopCondition());
    }

    public Shop getInfoById(Long id) {
        return ShopMapperStruct.INSTANCE.po2Entity(shopRepositoryService.getShopById(id));
    }

    public List<Shop> listAllShop() {
        return ShopMapperStruct.INSTANCE.po2Entity4List(shopRepositoryService.list(new ShopCondition()));
    }

    public List<Shop> listShopByIds(List<Long> ids) {
        ShopCondition shopCondition = new ShopCondition();
        shopCondition.setIds(ids);
        return ShopMapperStruct.INSTANCE.po2Entity4List(shopRepositoryService.list(shopCondition));
    }

    public Map<Long, Shop> groupById(List<Shop> shops) {
        return shops.stream().collect(Collectors.toMap(Shop::getId, Function.identity()));
    }

    /**
     * 查询所属城市门店
     */
    public List<Shop> getShopByCitiesId(Long cityId) {
        ShopCondition condition = new ShopCondition();
        condition.setCityId(cityId);
        return ShopMapperStruct.INSTANCE.po2Entity4List(shopRepositoryService.list(condition));
    }

    /**
     * 查询所属城市门店
     */
    public List<Shop> getListByCondition(ShopCondition condition) {
        return ShopMapperStruct.INSTANCE.po2Entity4List(shopRepositoryService.list(condition));
    }


    public String getShopScore(Long shopId) {
        List<Massagist> massagistList = massagistService.getMassagistListByShopId(shopId);
        return buildShopScore(massagistList);

    }

    public String getShopScore(List<Massagist> massagistList) {
        return buildShopScore(massagistList);

    }

    public String buildShopScore(List<Massagist> massagistList) {
        String defaultStr = "5.0";
        if (CollectionUtil.isNotEmpty(massagistList)) {
            List<Massagist> evaluateMassagistList = massagistList.stream().filter(f -> Convert.toDouble(f.getScore(), 0d) > 0).toList();
            if (CollectionUtil.isNotEmpty(evaluateMassagistList)) {
                //评分总和
                double dou = evaluateMassagistList.stream().mapToDouble(a -> Convert.toDouble(a.getScore())).sum();
                BigDecimal shopScoreDec = BigDecimal.valueOf(dou);
                if (shopScoreDec.compareTo(BigDecimal.ZERO) == 0) return defaultStr;
                //  门店技师评分总和 / 技师人数
                shopScoreDec = shopScoreDec.divide(BigDecimal.valueOf(evaluateMassagistList.size()), 1, RoundingMode.UP);
                if (Convert.toDouble(shopScoreDec.toString()) > 5d) return defaultStr;
                return Convert.toStr(shopScoreDec.toString(), defaultStr);
            }
        }
        return defaultStr;

    }

    public ShopIncomeDTO getShopIncomeDetailDTO(Long shopId, String beginDate, String endDate) {
        List<OrderInfo> orderInfos = getOverOrderList(shopId, beginDate, endDate);
        List<Profit> profits = profitService.queryProfitByShopId(shopId, beginDate, endDate);
        ShopIncomeDTO shopIncomeDTO = new ShopIncomeDTO();
        getPerformance4Shop(orderInfos, shopIncomeDTO);
        getIncome4Shop(profits, shopIncomeDTO);
        return shopIncomeDTO;
    }

    /**
     * 查询出技师在指定时间内的订单
     *
     * @param shopId
     * @param beginDate
     * @return
     */
    public List<OrderInfo> getOverOrderList(long shopId, String beginDate, String endDate) {
        OrderInfoCondition condition = new OrderInfoCondition();
        condition.setShopId(shopId);
        condition.setBeginSettlementTime(beginDate);
        condition.setEndSettlementTime(endDate);
        return orderService.orderList(condition);
    }

    /**
     * 计算门店的业绩
     * 已完成订单实际支付金额(包含加钟费用) + 已取消订单(用户原因)扣除的出行费用
     *
     * @return
     */
    public void getPerformance4Shop(List<OrderInfo> orderInfos, ShopIncomeDTO shopIncomeDTO) {
        int performance = 0;
        if (CollUtil.isNotEmpty(orderInfos)) {
            //已完成订单
            List<OrderInfo> complete = orderInfos.stream().filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$40.getCode())).toList();
            //已取消订单（技师已出发或已到达）
            List<OrderInfo> cancel = orderInfos.stream().filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$99.getCode())
                    && (Objects.equals(orderInfo.getOrderOperStatus(), OrderOperStatusEnum.$20.getCode())
                    || Objects.equals(orderInfo.getOrderOperStatus(), OrderOperStatusEnum.$30.getCode()))).toList();
            if (CollUtil.isNotEmpty(complete)) {
                OrderInfo.OrderExtCount orderExtCount = OrderInfo.gainOrderExtCount(orderInfos);
                Integer extraIncome = orderExtCount.getMoney();
                //已完成订单实际支付金额
                Integer income = complete.stream().map(OrderInfo::getOrderPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum);
                performance += extraIncome;
                performance += income;
                shopIncomeDTO.setExtraCount(orderExtCount.getCount());
                shopIncomeDTO.setExtraRatio(orderExtCount.getRatio());
            }
            if (CollUtil.isNotEmpty(cancel)) {
                //已取消订单(用户原因)扣除的出行费用
                Integer travelIncome = cancel.stream().map(OrderInfo::getTravelPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum);
                performance += travelIncome;
            }
            shopIncomeDTO.setCurrentPerformance(performance);
        }
    }

    /**
     * 计算门店的收入
     *
     * @return
     */
    public void getIncome4Shop(List<Profit> profits, ShopIncomeDTO shopIncomeDTO) {
        int income = 0;
        if (CollUtil.isNotEmpty(profits)) {
            //月补偿分润
            int massagistMonthIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(0))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getShopIncome(), 0)).sum();
            //项目收入
            int massagistIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(1))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getShopIncome(), 0)).sum();
            //加钟收入
            int massagistExtsIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(2))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getShopIncome(), 0)).sum();

            income += massagistMonthIncome;
            income += massagistIncome;
            income += massagistExtsIncome;
            shopIncomeDTO.setCurrentIncome(income);
        }
    }

    public List<Shop> shopList(ShopQuery query) {
        ShopCondition condition = ShopMapperStruct.INSTANCE.query2Condition(query);
        List<Shop> shopList = ShopMapperStruct.INSTANCE.po2Entity4List(shopRepositoryService.shopList(condition));
        setCity(shopList);
        setRule(shopList);
        return shopList;
    }


    /**
     * @description: 获取门店 业绩
     * @author: lig
     * @date: 2024-04-02
     */
    public Integer getShopPerf(OrderInfo orderInfo) {

        Date date = new Date();
        String beginDate = DateUtil.beginOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        String endDate = DateUtil.endOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        List<OrderInfo> orderInfos = getOverOrderList(orderInfo.getShopId(), beginDate, endDate);
        ////去掉当前操作订单 否则规则计算会错误
        //orderInfos = orderInfos.stream().filter(f1 -> !f1.getId().equals(orderInfo.getId())).toList();
        ShopIncomeDTO shopIncomeDTO = new ShopIncomeDTO();
        getPerformance4Shop(orderInfos, shopIncomeDTO);

        //门店 规则指标 - 业绩
        Integer perf = NumberUtil.nullToZero(shopIncomeDTO.getCurrentPerformance());
        return perf;


    }

    /**
     * @description: 校验门店 加钟率
     * @author: lig
     * @date: 2024-04-02
     */
    public Double getShopExtraRatio(long shopId) {

        Date date = new Date();
        String beginDate = DateUtil.beginOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        String endDate = DateUtil.endOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        List<OrderInfo> orderInfos = getOverOrderList(shopId, beginDate, endDate);

        //技师规则 - 指标 - 加钟率
        return OrderInfo.gainOrderExtCount(orderInfos).getRatio();

    }

    /**
     * 校验门店 好评率
     * 门店好评率=当月技师好评率总和/技师人数*100%
     *
     * @author: lig
     * @date: 2024-04-02
     */
    public Double getShopPositiveRatio(long shopId) {

        Date date = new Date();
        String beginDate = DateUtil.beginOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        String endDate = DateUtil.endOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        List<Massagist> massagistList = massagistService.getMassagistListByShopId(shopId);
        List<Long> massagistIds = massagistList.stream().map(Massagist::getId).toList();
        Map<Long, Double> m = massagistService.getMassagistPositiveRatio(massagistIds, beginDate, endDate);
        Stream<Map.Entry<Long, Double>> entryStream = m.entrySet().stream();
        double totalPositiveRatio = entryStream.mapToDouble(Map.Entry::getValue).sum();

        //门店 规则指标 - 好评率
        Double positiveRatio = NumberUtil.round(NumberUtil.div(totalPositiveRatio, massagistIds.size()), 2).doubleValue();
        return positiveRatio;

    }


}
